Skip to content

Add three MCP detections to the Suspicious MCP Activities story#4128

Open
eeee2345 wants to merge 3 commits into
splunk:developfrom
eeee2345:detections/mcp-suspicious-activities-expansion
Open

Add three MCP detections to the Suspicious MCP Activities story#4128
eeee2345 wants to merge 3 commits into
splunk:developfrom
eeee2345:detections/mcp-suspicious-activities-expansion

Conversation

@eeee2345

Copy link
Copy Markdown

This extends the Suspicious MCP Activities analytic story (created in #3895) with three contentctl-ng detections over the existing mcp:jsonrpc data source and the splunk/attack_data mcp.log dataset:

  • MCP Webhook Persistence Creation (create_webhook to an external URL; persistence / exfiltration channel; T1546)
  • MCP Suspicious File Deletion (delete_file, e.g. removing SECURITY.md; data destruction / defense evasion; T1485)
  • MCP Source Code Secret Search (search_code for credential patterns; credential harvesting; T1552.001)

Each detection uses the flat contentctl-ng schema, ends with its auto-named filter macro, joins the existing story via analytic_story, and ships a unit test that replays against mcp.log. ATR is cited only in references as URLs; rule counts are read from the live repo, not hard-coded.

Local validation

  • scripts/validate_yaml.py (yamllint + yamlfmt) PASS on all three files
  • contentctl-ng 0.7.0 build succeeds (schema, filter macros, uuid uniqueness, filename==name, HttpUrl references, real ATT&CK ids)
  • each search returns rows against mcp.log (5 / 5 / 16) so the unit-test replay has data to match

Note: the unit-test replay runs inside a Splunk container in CI. I verified the searches return rows against the dataset locally but could not run the container here, so that single check is confirmed only at the dataset-match level.

Disclosure: I maintain the open-source ATR project referenced in the detections.

Extends the Suspicious MCP Activities analytic story (created in splunk#3895) with
three contentctl-ng detections over the existing mcp:jsonrpc data source and
mcp.log dataset:

  - MCP Webhook Persistence Creation (create_webhook to an external URL -
    persistence / exfiltration channel, T1546)
  - MCP Suspicious File Deletion (delete_file, e.g. removing SECURITY.md -
    data destruction / defense evasion, T1485)
  - MCP Source Code Secret Search (search_code for credential patterns -
    credential harvesting, T1552.001)

Each detection follows the flat contentctl-ng schema, ends with its auto-named
filter macro, and includes a unit test that replays against the existing
splunk/attack_data mcp.log. Threat-rule context is referenced via the open,
MIT-licensed Agent Threat Rules project (rule counts read at runtime, not
hard-coded).

Validated locally: validate_yaml.py (yamllint + yamlfmt) PASS and
contentctl-ng 0.7.0 build succeeds; each search returns rows against mcp.log.

Signed-off-by: Adam Lin <adam@agentthreatrule.org>
@nasbench nasbench added this to the V6.2.0 milestone Jun 16, 2026
- MCP Server
search: |
`mcp_server` direction=inbound method=delete_file
| eval dest=host

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @eeee2345 : the search simply looks for file deletion and the description claims specifically for anomalous security related file delection. Please add appropriate filters to narrow down to the specific behaviour. Consider adding thresh hold levels

Address reviewer feedback on mcp_suspicious_file_deletion: the base
search matched any delete_file and deferred all narrowing to an empty
filter macro, which did not match the data-destruction / defense-evasion
framing in the description.

- mcp_suspicious_file_deletion: match each deleted path against the new
  editable mcp_security_relevant_deletion_targets macro (SECURITY.md,
  audit/access logs, .github/ CI config, key/secret files) and add a
  per-host deletion-burst threshold (>=10). The base search now only
  surfaces security-relevant deletions or high-volume bursts.
- mcp_webhook_persistence_creation: same over-broad pattern; narrow to
  webhooks whose host is not in the new editable mcp_trusted_webhook_domains
  allowlist, or that use a plaintext http endpoint or a raw IP destination.
- Add two editable narrowing macros (regex string definitions, mirroring
  o365_suspect_search_terms_regex) so tuning edits the logic surface, not a
  catch-all post-filter.

Validated with contentctl-ng build (schema + macro resolution) and the
repo YAML validation (yamllint + yamlfmt).
@eeee2345

Copy link
Copy Markdown
Author

@patel-bhavin thanks, fair call — you're right it was firing on any delete_file and leaning on the empty filter macro to do the narrowing. Pushed (22cb9e9): the search logic now does the work. It keys off an editable macro of security-relevant deletion targets (SECURITY.md, audit/access logs, .github/ CI config, IaC/pipeline, key/secret files) OR a deletion burst (count >= 10), via where is_security_relevant=1 OR is_deletion_burst=1, so routine single deletions no longer surface. I applied the same in-search narrowing to the over-broad webhook detection (untrusted-domain allowlist + plaintext http + raw-IP host), and left the secret-search one as-is since it already narrows in-query. contentctl-ng build passes locally.

One note on the red unit-testing check: it's the fork-PR Splunkbase-credentials gate — contentctl-ng install needs APPINSPECTUSERNAME/PASSWORD, and GitHub doesn't expose repo secrets to fork PRs, so the Splunkbase app download fails in CI. Not related to these detections; a maintainer run with creds should clear it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants